package com.ccl.iot.object;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;

import com.ccl.iot.privates.ListMap;

public class IOTSyncObjectInfo {
	/*
	 * 	Constants
	 */
	public final static int KIOT_INFO_TYPE_UNKNOWN = 0;
	public final static String KIOT_INFO_CONSTRACTOR_OBJECT = "()";
	
	public static class ObjectContainer{
		public String iID;
		public IOTSyncObjectInfo iObject;
		
		ObjectContainer(String aID){
			iID = aID;
		}
	}
	
	/*
	 * 	Static functions
	 */
	public static String DecodeName(String aName){
		if (aName != null){
			if (aName.endsWith(KIOT_INFO_CONSTRACTOR_OBJECT)){
				return aName.substring(0, aName.length() - KIOT_INFO_CONSTRACTOR_OBJECT.length());
			}
		}
		
		return aName;
	}
	
	public static String EncodeValue(Object aValue){
		if (aValue != null){
			if (aValue instanceof Byte){
				return "B" + aValue;
			}else if (aValue instanceof Short){
				return "S" + aValue;
			}else if (aValue instanceof Integer){
				return "I" + aValue;
			}else if (aValue instanceof Long){
				return "L" + aValue;
			}else if (aValue instanceof Float){
				return "F" + aValue;
			}else if (aValue instanceof Double){
				return "D" + aValue;
			}else if (aValue instanceof String){
				return "T" + aValue;
			}else if (aValue instanceof IOTSyncObjectInfo){
				return "O" + ((IOTSyncObjectInfo)aValue).getID();
			}
		}
		
		return null;
	}
	
	private static Object DecodeValue(String aValue){
		if (aValue != null){
			int tLength = aValue.length();
			
			if (tLength > 1){
				switch (aValue.charAt(0)){
					case 'B':{
						return Byte.valueOf(aValue.substring(1));
					}
					case 'S':{
						return Short.valueOf(aValue.substring(1));
					}
					case 'I':{
						return Integer.valueOf(aValue.substring(1));
					}
					case 'L':{
						return Long.valueOf(aValue.substring(1));
					}
					case 'F':{
						return Float.valueOf(aValue.substring(1));
					}
					case 'D':{
						return Double.valueOf(aValue.substring(1));
					}
					case 'T':{
						return aValue.substring(1);
					}
					case 'O':{
						return new ObjectContainer(aValue.substring(1));
					}
				}
			}else if (tLength == 1){
				if (aValue.charAt(0) == 'T'){
					return "";
				}
			}
		}
		
		return null;
	}
	
	/*
	 * 	Non-static functions
	 */
	private IOTInfoHeader iHeader = null;
	private int iInfoCount = 0;
	private int iCompletedInfoCount = 0;
	private int iNestInfoCount = 0;
	private ListMap<String, Object> iInfos = null;
	
	public IOTSyncObjectInfo(IOTInfoHeader aHeader){
		iHeader = aHeader;
	}
	
	public IOTSyncObjectInfo(String aPrefix, String aSyncID, HashMap<String, Object> aInfos, boolean aIncludeNest){
		if (aPrefix != null && aSyncID != null && aInfos != null){
			Iterator<Entry<String, Object>> tIterator = aInfos.entrySet().iterator();
			
			iHeader = IOTInfoHeader.Decode(aPrefix, aSyncID);
			
			while(tIterator.hasNext()){
				Entry<String, Object> tEntry = tIterator.next();
				
				if (tEntry != null){
					String tKey = tEntry.getKey();
					Object tValue = tEntry.getValue();
					
					if (tKey != null && tValue != null){
						if (iInfos == null){
							iInfos = new ListMap<String, Object>();
						}
						
						if (tValue instanceof IOTAbsSyncObject){
							if (aIncludeNest){
								tValue = new IOTSyncObjectInfo((IOTAbsSyncObject)tValue, aIncludeNest);
								
								iNestInfoCount++;
							}else{
								tValue = new IOTSyncObjectInfo(IOTInfoHeader.Decode(((IOTAbsSyncObject) tValue).getSyncInfoPrefix(), ((IOTAbsSyncObject) tValue).getSyncID()));
							}
						}
						
						iInfos.add(tKey, tValue);
						
						iInfoCount++;
						iCompletedInfoCount++;
					}
				}
			}
		}
	}
	
	public IOTSyncObjectInfo(IOTAbsSyncObject aObject, boolean aIncludeNest){
		this(aObject.getSyncInfoPrefix(), aObject.getSyncID(), aObject.getSyncInfos(), aIncludeNest);
	}
	
	public IOTInfoHeader getHeader(){
		return iHeader;
	}
	
	public String getID(){
		if (iHeader != null){
			return iHeader.getID();
		}
		
		return null;
	}
	
	public long getLongID(){
		if (iHeader != null){
			return iHeader.getLongID();
		}
		
		return 0;
	}
	
	public ListMap<String, Object> getAllInfo(){
		return iInfos;
	}
	
	public boolean isValid(boolean aIncludeNest){
		if (iInfoCount > 0){
			if (iInfos != null){
				if (iInfoCount == iCompletedInfoCount){
					return true;
				}else if (aIncludeNest == false){
					return iCompletedInfoCount + iNestInfoCount >= iInfoCount;
				}
			}
		}
		
		return false;
	}
	
	public boolean isValid(){
		return isValid(true);
	}
	
	public boolean hasNestInfo(){
		return iNestInfoCount > 0;
	}
	
	public int getNestLevel(){
		if (hasNestInfo()){
			int tMaxLevel = 0;
			
			for (int i = 0, tCount = iInfos.size(); i < tCount; i++){
				Object tObject = iInfos.getValueAt(i);
				
				if (tObject != null && tObject instanceof IOTSyncObjectInfo){
					int tLevel = ((IOTSyncObjectInfo)tObject).getNestLevel();
					
					if (tLevel > tMaxLevel){
						tMaxLevel = tLevel;
					}
				}
			}
			
			return tMaxLevel + 1;
		}
		
		return 0;
	}
	
	public boolean input(String aName, String aValue){
		if (aName != null && aValue != null && isValid() == false){
			if (KIOT_INFO_CONSTRACTOR_OBJECT.equals(aName)){
				if (iInfoCount == 0){
					iInfoCount = Integer.valueOf(aValue);
					
					return true;
				}
			}else{
				String tName = DecodeName(aName);
				
				if (iInfos == null){
					iInfos = new ListMap<String, Object>();
				}
				
				if (iInfos.containsKey(tName) == false){
					if (tName.length() == aName.length()){
						Object tObject = DecodeValue(aValue);
						
						if (tObject != null){
							iInfos.put(tName, tObject);
							if (tObject instanceof ObjectContainer){
								iNestInfoCount++;
							}else{
								iCompletedInfoCount++;
							}
							
							return true;
						}
					}
				}
			}
		}
		
		return false;
	}
	
	public boolean input(IOTSyncObjectInfo aObject){
		if (aObject != null && aObject.isValid() && iInfos != null){
			if (iCompletedInfoCount < iInfoCount){
				String tID = aObject.getID();
				
				if (tID != null){
					for (int i = 0, tCount = iInfos.size(); i < tCount; i++){
						Object tObject = iInfos.getValueAt(i);
						
						if (tObject != null && tObject instanceof ObjectContainer){
							ObjectContainer tContainer = (ObjectContainer)tObject;
							
							if (tID.equals(tContainer.iID)){
								iInfos.put(iInfos.getKeyAt(i), aObject);
								iCompletedInfoCount++;
								
								return true;
							}
						}
					}
				}
			}
		}
		
		return false;
	}
	
	public String getOutputName(String aName){
		return IOTInfoHeader.Encode(getID(), aName);
	}
	
	public HashMap<String, String> output(boolean aIncludeNest){
		if (isValid()){
			String tID = getID();
			HashMap<String, String> tInfos = new HashMap<String, String>();
			
			tInfos.put(IOTInfoHeader.Encode(tID, KIOT_INFO_CONSTRACTOR_OBJECT), String.valueOf(iInfoCount));
			
			for (int i = 0; i < iInfoCount; i++){
				Object tObject = iInfos.getValueAt(i);
				
				if (tObject != null){
					if (aIncludeNest && tObject instanceof IOTSyncObjectInfo){
						HashMap<String, String> tSubInfos = ((IOTSyncObjectInfo)tObject).output(aIncludeNest);
						
						if (tSubInfos != null && tSubInfos.size() > 0){
							tInfos.putAll(tSubInfos);
						}
					}
					
					tInfos.put(IOTInfoHeader.Encode(tID, iInfos.getKeyAt(i)), EncodeValue(tObject));
				}
			}
			
			return tInfos;
		}
		
		return null;
	}
}
